package com.java.simple.smallspring.jdbc.datasource;

import com.java.simple.smallspring.jdbc.CannotGetJdbcConnectionException;
import com.java.simple.smallspring.tx.transaction.support.TransactionSynchronizationManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Objects;

/**
 * @author zhoujunlin
 * @date 2022年11月19日 21:44
 * @desc
 */
public abstract class DataSourceUtils {

    private static final Logger logger = LoggerFactory.getLogger(DataSourceUtils.class);

    public static Connection getConnection(DataSource dataSource) {
        try {
            return doGetConnection(dataSource);
        } catch (SQLException e) {
            throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection", e);
        }
    }

    public static Connection doGetConnection(DataSource dataSource) throws SQLException {
        ConnectionHolder connectionHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
        if (Objects.nonNull(connectionHolder) && connectionHolder.hasConnection()) {
            return connectionHolder.getConnection();
        }
        return fetchConnection(dataSource);
    }

    private static Connection fetchConnection(DataSource dataSource) throws SQLException {
        Connection connection = dataSource.getConnection();
        if (Objects.isNull(connection)) {
            throw new IllegalArgumentException("DataSource return null from getConnection():" + dataSource);
        }
        return connection;
    }

    public static void releaseConnection(Connection connection, DataSource dataSource) {
        try {
            deReleaseConnection(connection, dataSource);
        } catch (SQLException ex) {
            logger.debug("Could not close JDBC Connection", ex);
        } catch (Throwable t) {
            logger.debug("Unexpected exception on closing JDBC Connection", t);
        }
    }

    public static void deReleaseConnection(Connection connection, DataSource dataSource) throws SQLException {
        if (Objects.isNull(connection)) {
            return;
        }
        doCloseConnection(connection, dataSource);
    }

    public static void doCloseConnection(Connection connection, DataSource dataSource) throws SQLException {
        connection.close();
    }
}
